<!--
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2022-11-11 20:21:23
 * @FilePath: \web面试题\防抖.html
 * @email: 492934056@qq.com
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>js防抖</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      body {
        padding: 20px;
      }

      .debounceWarper .debounceItem {
        display: flex;
        margin-top: 20px;
      }
      .debounceWarper .debounceItem .debounceItem_label {
        width: 230px;
      }

      .tooltips {
        display: block;
        color: red;
        font-size: 12px;
        margin-top: 2px;
      }
    </style>
  </head>
  <body>
    防抖：防抖就是在单位时间内只执行最后一次操作
    <!-- 防抖：控制高频事件 -->
    <div class="debounceWarper">
      <div class="debounceItem">
        <span class="debounceItem_label">不做防抖的输入框：</span>
        <input class="debounceItem_value" id="input1" type="text" />
      </div>
      <div class="debounceItem">
        <span class="debounceItem_label">全局timer做防抖的输入框：</span>
        <input class="debounceItem_value" id="input2" type="text" />
      </div>
      <span class="tooltips"
        >这里用setTimeout来判断是否达到运行时间了，但是用了全局timer来标识。</span
      >
      <span class="tooltips"
        >思考：1.如果有多个该怎么样，要怎么封装才好呢？</span
      >
      <span class="tooltips"
        >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        2.另外，业务跟功能夹杂在一起了，能不能抽取出防抖这个功能呢？</span
      >

      <div class="debounceItem">
        <span class="debounceItem_label">闭包做防抖的输入框：</span>
        <input class="debounceItem_value" id="input3" type="text" />
      </div>
      <div class="debounceItem">
        <span class="debounceItem_label">闭包做防抖的输入框：</span>
        <input class="debounceItem_value" id="input4" type="text" />
      </div>
    </div>

    <script>
      // -----------------------不做防抖的输入框：---------------------- //
      let input1 = document.getElementById("input1");
      input1.addEventListener("input", function (e) {
        // 不能使用箭头函数，避免作用域提升
        console.log("第一个不做防抖的输入框：", this.value);
      });

      // -----------------------全局timer做防抖的输入框：---------------------- //
      let input2 = document.getElementById("input2");
      let timer = null;
      input2.addEventListener("input", function (e) {
        // 如果已经有事件了，则清空计时器重新执行新的，保证是最新一次执行
        if (timer != null) {
          clearTimeout(timer);
        }
        // 这里需要箭头函数，这样就可以提升到input2这个作用域
        timer = setTimeout(() => {
          console.log("e:", e);
          console.log("全局timer制作的防抖：", this.value);
        }, 1000);
      });

      // -----------------------闭包做防抖的输入框：---------------------- //
      let input3 = document.getElementById("input3");
      input3.addEventListener(
        "input",
        // 这边新建了一个闭包
        debounce(function (e) {
          console.log("e:", e);
          console.log("闭包做的防抖 input3：", this.value);
        }, 1000)
      );

      let input4 = document.getElementById("input4");
      input4.addEventListener(
        "input",
        // 这边新建了另外一个闭包
        debounce(function (e) {
          // console.log("e:", e);
          console.log("闭包做的防抖 input4：", this.value);
        }, 1000)
      );

      /**
       * @author: Penk
       * @description: 防抖，通过闭包保存timer变量
       * @param {*} fn
       * @param {*} timeout
       * @return {*}
       */
      function debounce(fn, timeout) {
        let timer = null;
        return function (e) {
          // 如果已经有事件了，则清空计时器重新执行新的，保证是最新一次执行
          if (timer != null) {
            clearTimeout(timer);
          }
          // 这里需要箭头函数，这样就可以提升到input2这个作用域
          timer = setTimeout(() => {
            fn.call(this, e);
          }, timeout);
        };
      }
    </script>
  </body>
</html>
